{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# How to transform data into factors"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Based on a conceptual understanding of key factor categories, their rationale and popular metrics, a key task is to identify new factors that may better capture the risks embodied by the return drivers laid out previously, or to find new ones. \n",
    "\n",
    "In either case, it will be important to compare the performance of innovative factors to that of known factors to identify incremental signal gains."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We create the dataset here and store it in our [data](../../data) folder to facilitate reuse in later chapters."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Imports & Settings"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:02.668823Z",
     "start_time": "2020-06-16T21:40:02.666706Z"
    }
   },
   "outputs": [],
   "source": [
    "import warnings\n",
    "warnings.filterwarnings('ignore')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:04.560323Z",
     "start_time": "2020-06-16T21:40:02.673361Z"
    }
   },
   "outputs": [],
   "source": [
    "%matplotlib inline\n",
    "\n",
    "from datetime import datetime\n",
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "import pandas as pd\n",
    "import pandas_datareader.data as web\n",
    "from pyfinance.ols import PandasRollingOLS"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:04.567059Z",
     "start_time": "2020-06-16T21:40:04.562727Z"
    }
   },
   "outputs": [],
   "source": [
    "sns.set_style('whitegrid')\n",
    "idx = pd.IndexSlice"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Get Data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `assets.h5` store can be generated using the the notebook [create_datasets](../../data/create_datasets.ipynb) in the [data](../../data) directory in the root directory of this repo for instruction to download the following dataset."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We load the Quandl stock price datasets covering the US equity markets 2000-18 using `pd.IndexSlice` to perform a slice operation on the `pd.MultiIndex`, select the adjusted close price and unpivot the column to convert the DataFrame to wide format with tickers in the columns and timestamps in the rows:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Set data store location:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:04.581618Z",
     "start_time": "2020-06-16T21:40:04.569726Z"
    }
   },
   "outputs": [],
   "source": [
    "DATA_STORE = '../data/assets.h5'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:04.589158Z",
     "start_time": "2020-06-16T21:40:04.583674Z"
    }
   },
   "outputs": [],
   "source": [
    "START = 2000\n",
    "END = 2018"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:15.246042Z",
     "start_time": "2020-06-16T21:40:04.590671Z"
    }
   },
   "outputs": [],
   "source": [
    "with pd.HDFStore(DATA_STORE) as store:\n",
    "    prices = (store['quandl/wiki/prices']\n",
    "              .loc[idx[str(START):str(END), :], 'adj_close']\n",
    "              .unstack('ticker'))\n",
    "    stocks = store['us_equities/stocks'].loc[:, ['marketcap', 'ipoyear', 'sector']]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:15.586026Z",
     "start_time": "2020-06-16T21:40:15.252928Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "DatetimeIndex: 4706 entries, 2000-01-03 to 2018-03-27\n",
      "Columns: 3199 entries, A to ZUMZ\n",
      "dtypes: float64(3199)\n",
      "memory usage: 114.9 MB\n"
     ]
    }
   ],
   "source": [
    "prices.info()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:15.610681Z",
     "start_time": "2020-06-16T21:40:15.598902Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "Index: 6834 entries, PIH to ZYME\n",
      "Data columns (total 3 columns):\n",
      " #   Column     Non-Null Count  Dtype  \n",
      "---  ------     --------------  -----  \n",
      " 0   marketcap  5766 non-null   float64\n",
      " 1   ipoyear    3038 non-null   float64\n",
      " 2   sector     5288 non-null   object \n",
      "dtypes: float64(2), object(1)\n",
      "memory usage: 213.6+ KB\n"
     ]
    }
   ],
   "source": [
    "stocks.info()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Keep data with stock info"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Remove `stocks` duplicates and align index names for later joining."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:15.631626Z",
     "start_time": "2020-06-16T21:40:15.625456Z"
    }
   },
   "outputs": [],
   "source": [
    "stocks = stocks[~stocks.index.duplicated()]\n",
    "stocks.index.name = 'ticker'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Get tickers with both price information and metdata"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:15.654447Z",
     "start_time": "2020-06-16T21:40:15.647285Z"
    }
   },
   "outputs": [],
   "source": [
    "shared = prices.columns.intersection(stocks.index)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:15.681483Z",
     "start_time": "2020-06-16T21:40:15.663957Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "Index: 2412 entries, A to ZUMZ\n",
      "Data columns (total 3 columns):\n",
      " #   Column     Non-Null Count  Dtype  \n",
      "---  ------     --------------  -----  \n",
      " 0   marketcap  2407 non-null   float64\n",
      " 1   ipoyear    1065 non-null   float64\n",
      " 2   sector     2372 non-null   object \n",
      "dtypes: float64(2), object(1)\n",
      "memory usage: 75.4+ KB\n"
     ]
    }
   ],
   "source": [
    "stocks = stocks.loc[shared, :]\n",
    "stocks.info()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:15.881925Z",
     "start_time": "2020-06-16T21:40:15.691734Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "DatetimeIndex: 4706 entries, 2000-01-03 to 2018-03-27\n",
      "Columns: 2412 entries, A to ZUMZ\n",
      "dtypes: float64(2412)\n",
      "memory usage: 86.6 MB\n"
     ]
    }
   ],
   "source": [
    "prices = prices.loc[:, shared]\n",
    "prices.info()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:15.919291Z",
     "start_time": "2020-06-16T21:40:15.906590Z"
    }
   },
   "outputs": [],
   "source": [
    "assert prices.shape[1] == stocks.shape[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Create monthly return series"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To reduce training time and experiment with strategies for longer time horizons, we convert the business-daily data to month-end frequency using the available adjusted close price:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:16.028139Z",
     "start_time": "2020-06-16T21:40:15.935843Z"
    }
   },
   "outputs": [],
   "source": [
    "monthly_prices = prices.resample('M').last()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To capture time series dynamics that reflect, for example, momentum patterns, we compute historical returns using the method `.pct_change(n_periods)`, that is, returns over various monthly periods as identified by lags.\n",
    "\n",
    "We then convert the wide result back to long format with the `.stack()` method, use `.pipe()` to apply the `.clip()` method to the resulting `DataFrame`, and winsorize returns at the [1%, 99%] levels; that is, we cap outliers at these percentiles.\n",
    "\n",
    "Finally, we normalize returns using the geometric average. After using `.swaplevel()` to change the order of the `MultiIndex` levels, we obtain compounded monthly returns for six periods ranging from 1 to 12 months:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:16.216076Z",
     "start_time": "2020-06-16T21:40:16.042248Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "DatetimeIndex: 219 entries, 2000-01-31 to 2018-03-31\n",
      "Freq: M\n",
      "Columns: 2412 entries, A to ZUMZ\n",
      "dtypes: float64(2412)\n",
      "memory usage: 4.0 MB\n"
     ]
    }
   ],
   "source": [
    "monthly_prices.info()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:27.231947Z",
     "start_time": "2020-06-16T21:40:16.228511Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "MultiIndex: 399525 entries, ('A', Timestamp('2001-01-31 00:00:00', freq='M')) to ('ZUMZ', Timestamp('2018-03-31 00:00:00', freq='M'))\n",
      "Data columns (total 6 columns):\n",
      " #   Column      Non-Null Count   Dtype  \n",
      "---  ------      --------------   -----  \n",
      " 0   return_1m   399525 non-null  float64\n",
      " 1   return_2m   399525 non-null  float64\n",
      " 2   return_3m   399525 non-null  float64\n",
      " 3   return_6m   399525 non-null  float64\n",
      " 4   return_9m   399525 non-null  float64\n",
      " 5   return_12m  399525 non-null  float64\n",
      "dtypes: float64(6)\n",
      "memory usage: 19.8+ MB\n"
     ]
    }
   ],
   "source": [
    "outlier_cutoff = 0.01\n",
    "data = pd.DataFrame()\n",
    "lags = [1, 2, 3, 6, 9, 12]\n",
    "for lag in lags:\n",
    "    data[f'return_{lag}m'] = (monthly_prices\n",
    "                           .pct_change(lag)\n",
    "                           .stack()\n",
    "                           .pipe(lambda x: x.clip(lower=x.quantile(outlier_cutoff),\n",
    "                                                  upper=x.quantile(1-outlier_cutoff)))\n",
    "                           .add(1)\n",
    "                           .pow(1/lag)\n",
    "                           .sub(1)\n",
    "                           )\n",
    "data = data.swaplevel().dropna()\n",
    "data.info()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Drop stocks with less than 10 yrs of returns"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:32.958835Z",
     "start_time": "2020-06-16T21:40:27.238196Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "MultiIndex: 360752 entries, ('A', Timestamp('2001-01-31 00:00:00', freq='M')) to ('ZUMZ', Timestamp('2018-03-31 00:00:00', freq='M'))\n",
      "Data columns (total 6 columns):\n",
      " #   Column      Non-Null Count   Dtype  \n",
      "---  ------      --------------   -----  \n",
      " 0   return_1m   360752 non-null  float64\n",
      " 1   return_2m   360752 non-null  float64\n",
      " 2   return_3m   360752 non-null  float64\n",
      " 3   return_6m   360752 non-null  float64\n",
      " 4   return_9m   360752 non-null  float64\n",
      " 5   return_12m  360752 non-null  float64\n",
      "dtypes: float64(6)\n",
      "memory usage: 17.9+ MB\n"
     ]
    }
   ],
   "source": [
    "min_obs = 120\n",
    "nobs = data.groupby(level='ticker').size()\n",
    "keep = nobs[nobs>min_obs].index\n",
    "\n",
    "data = data.loc[idx[keep,:], :]\n",
    "data.info()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:33.200122Z",
     "start_time": "2020-06-16T21:40:32.964996Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>return_1m</th>\n",
       "      <th>return_2m</th>\n",
       "      <th>return_3m</th>\n",
       "      <th>return_6m</th>\n",
       "      <th>return_9m</th>\n",
       "      <th>return_12m</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>count</th>\n",
       "      <td>360752.000000</td>\n",
       "      <td>360752.000000</td>\n",
       "      <td>360752.000000</td>\n",
       "      <td>360752.000000</td>\n",
       "      <td>360752.000000</td>\n",
       "      <td>360752.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>mean</th>\n",
       "      <td>0.012255</td>\n",
       "      <td>0.009213</td>\n",
       "      <td>0.008181</td>\n",
       "      <td>0.007025</td>\n",
       "      <td>0.006552</td>\n",
       "      <td>0.006296</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>std</th>\n",
       "      <td>0.114236</td>\n",
       "      <td>0.081170</td>\n",
       "      <td>0.066584</td>\n",
       "      <td>0.048474</td>\n",
       "      <td>0.039897</td>\n",
       "      <td>0.034792</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>min</th>\n",
       "      <td>-0.329564</td>\n",
       "      <td>-0.255452</td>\n",
       "      <td>-0.214783</td>\n",
       "      <td>-0.162063</td>\n",
       "      <td>-0.131996</td>\n",
       "      <td>-0.114283</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>25%</th>\n",
       "      <td>-0.046464</td>\n",
       "      <td>-0.030716</td>\n",
       "      <td>-0.023961</td>\n",
       "      <td>-0.014922</td>\n",
       "      <td>-0.011182</td>\n",
       "      <td>-0.009064</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>50%</th>\n",
       "      <td>0.009448</td>\n",
       "      <td>0.009748</td>\n",
       "      <td>0.009744</td>\n",
       "      <td>0.009378</td>\n",
       "      <td>0.008982</td>\n",
       "      <td>0.008726</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>75%</th>\n",
       "      <td>0.066000</td>\n",
       "      <td>0.049249</td>\n",
       "      <td>0.042069</td>\n",
       "      <td>0.031971</td>\n",
       "      <td>0.027183</td>\n",
       "      <td>0.024615</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>max</th>\n",
       "      <td>0.430943</td>\n",
       "      <td>0.281819</td>\n",
       "      <td>0.221789</td>\n",
       "      <td>0.154555</td>\n",
       "      <td>0.124718</td>\n",
       "      <td>0.106371</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "           return_1m      return_2m      return_3m      return_6m  \\\n",
       "count  360752.000000  360752.000000  360752.000000  360752.000000   \n",
       "mean        0.012255       0.009213       0.008181       0.007025   \n",
       "std         0.114236       0.081170       0.066584       0.048474   \n",
       "min        -0.329564      -0.255452      -0.214783      -0.162063   \n",
       "25%        -0.046464      -0.030716      -0.023961      -0.014922   \n",
       "50%         0.009448       0.009748       0.009744       0.009378   \n",
       "75%         0.066000       0.049249       0.042069       0.031971   \n",
       "max         0.430943       0.281819       0.221789       0.154555   \n",
       "\n",
       "           return_9m     return_12m  \n",
       "count  360752.000000  360752.000000  \n",
       "mean        0.006552       0.006296  \n",
       "std         0.039897       0.034792  \n",
       "min        -0.131996      -0.114283  \n",
       "25%        -0.011182      -0.009064  \n",
       "50%         0.008982       0.008726  \n",
       "75%         0.027183       0.024615  \n",
       "max         0.124718       0.106371  "
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data.describe()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:35.192980Z",
     "start_time": "2020-06-16T21:40:33.206081Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 720x720 with 4 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# cmap = sns.diverging_palette(10, 220, as_cmap=True)\n",
    "sns.clustermap(data.corr('spearman'), annot=True, center=0, cmap='Blues');"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We are left with 1,670 tickers."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:35.234259Z",
     "start_time": "2020-06-16T21:40:35.194435Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1838"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data.index.get_level_values('ticker').nunique()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Rolling Factor Betas"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We will introduce the Fama—French data to estimate the exposure of assets to common risk factors using linear regression in [Chapter 8, Time Series Models]([](../../08_time_series_models))."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The five Fama—French factors, namely market risk, size, value, operating profitability, and investment have been shown empirically to explain asset returns and are commonly used to assess the risk/return profile of portfolios. Hence, it is natural to include past factor exposures as financial features in models that aim to predict future returns."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can access the historical factor returns using the `pandas-datareader` and estimate historical exposures using the `PandasRollingOLS` rolling linear regression functionality in the `pyfinance` library as follows:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Use Fama-French research factors to estimate the factor exposures of the stock in the dataset to the 5 factors market risk, size, value, operating profitability and investment."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:35.392523Z",
     "start_time": "2020-06-16T21:40:35.235572Z"
    },
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "DatetimeIndex: 244 entries, 2000-01-31 to 2020-04-30\n",
      "Freq: M\n",
      "Data columns (total 5 columns):\n",
      " #   Column  Non-Null Count  Dtype  \n",
      "---  ------  --------------  -----  \n",
      " 0   Mkt-RF  244 non-null    float64\n",
      " 1   SMB     244 non-null    float64\n",
      " 2   HML     244 non-null    float64\n",
      " 3   RMW     244 non-null    float64\n",
      " 4   CMA     244 non-null    float64\n",
      "dtypes: float64(5)\n",
      "memory usage: 11.4 KB\n"
     ]
    }
   ],
   "source": [
    "factors = ['Mkt-RF', 'SMB', 'HML', 'RMW', 'CMA']\n",
    "factor_data = web.DataReader('F-F_Research_Data_5_Factors_2x3', 'famafrench', start='2000')[0].drop('RF', axis=1)\n",
    "factor_data.index = factor_data.index.to_timestamp()\n",
    "factor_data = factor_data.resample('M').last().div(100)\n",
    "factor_data.index.name = 'date'\n",
    "factor_data.info()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:35.603073Z",
     "start_time": "2020-06-16T21:40:35.397091Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "MultiIndex: 360752 entries, ('A', Timestamp('2001-01-31 00:00:00', freq='M')) to ('ZUMZ', Timestamp('2018-03-31 00:00:00', freq='M'))\n",
      "Data columns (total 6 columns):\n",
      " #   Column     Non-Null Count   Dtype  \n",
      "---  ------     --------------   -----  \n",
      " 0   Mkt-RF     360752 non-null  float64\n",
      " 1   SMB        360752 non-null  float64\n",
      " 2   HML        360752 non-null  float64\n",
      " 3   RMW        360752 non-null  float64\n",
      " 4   CMA        360752 non-null  float64\n",
      " 5   return_1m  360752 non-null  float64\n",
      "dtypes: float64(6)\n",
      "memory usage: 17.9+ MB\n"
     ]
    }
   ],
   "source": [
    "factor_data = factor_data.join(data['return_1m']).sort_index()\n",
    "factor_data.info()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:41.278324Z",
     "start_time": "2020-06-16T21:40:35.607380Z"
    }
   },
   "outputs": [],
   "source": [
    "T = 24\n",
    "betas = (factor_data\n",
    "         .groupby(level='ticker', group_keys=False)\n",
    "         .apply(lambda x: PandasRollingOLS(window=min(T, x.shape[0]-1), y=x.return_1m, x=x.drop('return_1m', axis=1)).beta))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:41.635859Z",
     "start_time": "2020-06-16T21:40:41.288895Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>Mkt-RF</th>\n",
       "      <th>SMB</th>\n",
       "      <th>HML</th>\n",
       "      <th>RMW</th>\n",
       "      <th>CMA</th>\n",
       "      <th>total</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>count</th>\n",
       "      <td>318478.000000</td>\n",
       "      <td>318478.000000</td>\n",
       "      <td>318478.000000</td>\n",
       "      <td>318478.000000</td>\n",
       "      <td>318478.000000</td>\n",
       "      <td>318478.000000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>mean</th>\n",
       "      <td>0.979917</td>\n",
       "      <td>0.625992</td>\n",
       "      <td>0.126318</td>\n",
       "      <td>-0.072697</td>\n",
       "      <td>0.017344</td>\n",
       "      <td>1.676873</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>std</th>\n",
       "      <td>0.916408</td>\n",
       "      <td>1.257130</td>\n",
       "      <td>1.575346</td>\n",
       "      <td>2.009677</td>\n",
       "      <td>2.201823</td>\n",
       "      <td>3.605859</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>min</th>\n",
       "      <td>-9.296963</td>\n",
       "      <td>-10.173468</td>\n",
       "      <td>-15.603620</td>\n",
       "      <td>-24.799548</td>\n",
       "      <td>-18.500054</td>\n",
       "      <td>-35.104249</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>25%</th>\n",
       "      <td>0.461398</td>\n",
       "      <td>-0.118324</td>\n",
       "      <td>-0.695309</td>\n",
       "      <td>-1.014692</td>\n",
       "      <td>-1.098085</td>\n",
       "      <td>-0.158014</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>50%</th>\n",
       "      <td>0.929132</td>\n",
       "      <td>0.543081</td>\n",
       "      <td>0.101234</td>\n",
       "      <td>0.041746</td>\n",
       "      <td>0.044000</td>\n",
       "      <td>1.630633</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>75%</th>\n",
       "      <td>1.447176</td>\n",
       "      <td>1.304617</td>\n",
       "      <td>0.930624</td>\n",
       "      <td>0.983729</td>\n",
       "      <td>1.154911</td>\n",
       "      <td>3.518445</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>max</th>\n",
       "      <td>10.423569</td>\n",
       "      <td>10.265619</td>\n",
       "      <td>13.134683</td>\n",
       "      <td>17.643528</td>\n",
       "      <td>16.921621</td>\n",
       "      <td>35.743201</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "              Mkt-RF            SMB            HML            RMW  \\\n",
       "count  318478.000000  318478.000000  318478.000000  318478.000000   \n",
       "mean        0.979917       0.625992       0.126318      -0.072697   \n",
       "std         0.916408       1.257130       1.575346       2.009677   \n",
       "min        -9.296963     -10.173468     -15.603620     -24.799548   \n",
       "25%         0.461398      -0.118324      -0.695309      -1.014692   \n",
       "50%         0.929132       0.543081       0.101234       0.041746   \n",
       "75%         1.447176       1.304617       0.930624       0.983729   \n",
       "max        10.423569      10.265619      13.134683      17.643528   \n",
       "\n",
       "                 CMA          total  \n",
       "count  318478.000000  318478.000000  \n",
       "mean        0.017344       1.676873  \n",
       "std         2.201823       3.605859  \n",
       "min       -18.500054     -35.104249  \n",
       "25%        -1.098085      -0.158014  \n",
       "50%         0.044000       1.630633  \n",
       "75%         1.154911       3.518445  \n",
       "max        16.921621      35.743201  "
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "betas.describe().join(betas.sum(1).describe().to_frame('total'))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:42.563309Z",
     "start_time": "2020-06-16T21:40:41.640793Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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slqt6tmzp+3ergcffLDC9h555BF17dpVEyZMqNZx4Nd5eXnJ399f06dPV58+fexdjtMLDw/X5s2blZubK0m6evWqpk6dqoMHD0r69f1VWlqqzMxMffDBB5o/f77mz5+vuLg4LV682C7jcDbZ2dmaNGmSiouLJUn+/v7y8fGRq6urpPLJho8//lhnz5697sTCNfXr16+WelGuTp06mj59ul577TWdPXtW0o3PiU2aNNGZM2d08OBBBQYGSpI6dOig+fPnc3uFAQEZTqFXr146efKk/P39Kyw3mUx666239Oabb+rChQtq3bq1xowZox9++OGG23vxxRd19OhR231bsL/IyEh9/fXXtkuMRi+//LKioqIUFRWlxMREO1TnXLy9vTV16lS99tprtsvuAQEB6tSpk22d6+2vDRs2KDAwULVr17Yti4qK0ieffHLDL9fif6N79+4KDg7WE088oZiYGA0aNEhjxoyRj4+PpPIvPV+4cEHh4eG/6Hvtcv+f/vQnDRw4UOPGjWP2uBo1bdpUsbGxSk9Pty270TmxcePGuv/++23fo+nUqZP27t3LDLKByXrta/gAAAAAmEEGAAAAjAjIAAAAgAEBGQAAADAgIAMAAAAGBGQAAADAgIAMAAAAGBCQAQAAAIP/AzmewDisQwHsAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<Figure size 720x720 with 4 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "cmap = sns.diverging_palette(10, 220, as_cmap=True)\n",
    "sns.clustermap(betas.corr(), annot=True, cmap=cmap, center=0);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:46.026266Z",
     "start_time": "2020-06-16T21:40:42.568188Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "MultiIndex: 360752 entries, ('A', Timestamp('2001-01-31 00:00:00', freq='M')) to ('ZUMZ', Timestamp('2018-03-31 00:00:00', freq='M'))\n",
      "Data columns (total 11 columns):\n",
      " #   Column      Non-Null Count   Dtype  \n",
      "---  ------      --------------   -----  \n",
      " 0   return_1m   360752 non-null  float64\n",
      " 1   return_2m   360752 non-null  float64\n",
      " 2   return_3m   360752 non-null  float64\n",
      " 3   return_6m   360752 non-null  float64\n",
      " 4   return_9m   360752 non-null  float64\n",
      " 5   return_12m  360752 non-null  float64\n",
      " 6   Mkt-RF      316640 non-null  float64\n",
      " 7   SMB         316640 non-null  float64\n",
      " 8   HML         316640 non-null  float64\n",
      " 9   RMW         316640 non-null  float64\n",
      " 10  CMA         316640 non-null  float64\n",
      "dtypes: float64(11)\n",
      "memory usage: 41.7+ MB\n"
     ]
    }
   ],
   "source": [
    "data = (data\n",
    "        .join(betas\n",
    "              .groupby(level='ticker')\n",
    "              .shift()))\n",
    "data.info()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Impute mean for missing factor betas"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:53.572793Z",
     "start_time": "2020-06-16T21:40:46.033057Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "MultiIndex: 360752 entries, ('A', Timestamp('2001-01-31 00:00:00', freq='M')) to ('ZUMZ', Timestamp('2018-03-31 00:00:00', freq='M'))\n",
      "Data columns (total 11 columns):\n",
      " #   Column      Non-Null Count   Dtype  \n",
      "---  ------      --------------   -----  \n",
      " 0   return_1m   360752 non-null  float64\n",
      " 1   return_2m   360752 non-null  float64\n",
      " 2   return_3m   360752 non-null  float64\n",
      " 3   return_6m   360752 non-null  float64\n",
      " 4   return_9m   360752 non-null  float64\n",
      " 5   return_12m  360752 non-null  float64\n",
      " 6   Mkt-RF      360752 non-null  float64\n",
      " 7   SMB         360752 non-null  float64\n",
      " 8   HML         360752 non-null  float64\n",
      " 9   RMW         360752 non-null  float64\n",
      " 10  CMA         360752 non-null  float64\n",
      "dtypes: float64(11)\n",
      "memory usage: 41.7+ MB\n"
     ]
    }
   ],
   "source": [
    "data.loc[:, factors] = data.groupby('ticker')[factors].apply(lambda x: x.fillna(x.mean()))\n",
    "data.info()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Momentum factors"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We can use these results to compute momentum factors based on the difference between returns over longer periods and the most recent monthly return, as well as for the difference between 3 and 12 month returns as follows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:53.607150Z",
     "start_time": "2020-06-16T21:40:53.577727Z"
    }
   },
   "outputs": [],
   "source": [
    "for lag in [2,3,6,9,12]:\n",
    "    data[f'momentum_{lag}'] = data[f'return_{lag}m'].sub(data.return_1m)\n",
    "data[f'momentum_3_12'] = data[f'return_12m'].sub(data.return_3m)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Date Indicators"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:53.763723Z",
     "start_time": "2020-06-16T21:40:53.608546Z"
    }
   },
   "outputs": [],
   "source": [
    "dates = data.index.get_level_values('date')\n",
    "data['year'] = dates.year\n",
    "data['month'] = dates.month"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Lagged returns"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To use lagged values as input variables or features associated with the current observations, we use the .shift() method to move historical returns up to the current period:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:54.391769Z",
     "start_time": "2020-06-16T21:40:53.765084Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "MultiIndex: 360752 entries, ('A', Timestamp('2001-01-31 00:00:00', freq='M')) to ('ZUMZ', Timestamp('2018-03-31 00:00:00', freq='M'))\n",
      "Data columns (total 25 columns):\n",
      " #   Column         Non-Null Count   Dtype  \n",
      "---  ------         --------------   -----  \n",
      " 0   return_1m      360752 non-null  float64\n",
      " 1   return_2m      360752 non-null  float64\n",
      " 2   return_3m      360752 non-null  float64\n",
      " 3   return_6m      360752 non-null  float64\n",
      " 4   return_9m      360752 non-null  float64\n",
      " 5   return_12m     360752 non-null  float64\n",
      " 6   Mkt-RF         360752 non-null  float64\n",
      " 7   SMB            360752 non-null  float64\n",
      " 8   HML            360752 non-null  float64\n",
      " 9   RMW            360752 non-null  float64\n",
      " 10  CMA            360752 non-null  float64\n",
      " 11  momentum_2     360752 non-null  float64\n",
      " 12  momentum_3     360752 non-null  float64\n",
      " 13  momentum_6     360752 non-null  float64\n",
      " 14  momentum_9     360752 non-null  float64\n",
      " 15  momentum_12    360752 non-null  float64\n",
      " 16  momentum_3_12  360752 non-null  float64\n",
      " 17  year           360752 non-null  int64  \n",
      " 18  month          360752 non-null  int64  \n",
      " 19  return_1m_t-1  358914 non-null  float64\n",
      " 20  return_1m_t-2  357076 non-null  float64\n",
      " 21  return_1m_t-3  355238 non-null  float64\n",
      " 22  return_1m_t-4  353400 non-null  float64\n",
      " 23  return_1m_t-5  351562 non-null  float64\n",
      " 24  return_1m_t-6  349724 non-null  float64\n",
      "dtypes: float64(23), int64(2)\n",
      "memory usage: 80.2+ MB\n"
     ]
    }
   ],
   "source": [
    "for t in range(1, 7):\n",
    "    data[f'return_1m_t-{t}'] = data.groupby(level='ticker').return_1m.shift(t)\n",
    "data.info()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Target: Holding Period Returns"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Similarly, to compute returns for various holding periods, we use the normalized period returns computed previously and shift them back to align them with the current financial features"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:54.971089Z",
     "start_time": "2020-06-16T21:40:54.396090Z"
    }
   },
   "outputs": [],
   "source": [
    "for t in [1,2,3,6,12]:\n",
    "    data[f'target_{t}m'] = data.groupby(level='ticker')[f'return_{t}m'].shift(-t)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:55.176943Z",
     "start_time": "2020-06-16T21:40:54.988343Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th>target_1m</th>\n",
       "      <th>target_2m</th>\n",
       "      <th>target_3m</th>\n",
       "      <th>return_1m</th>\n",
       "      <th>return_2m</th>\n",
       "      <th>return_3m</th>\n",
       "      <th>return_1m_t-1</th>\n",
       "      <th>return_1m_t-2</th>\n",
       "      <th>return_1m_t-3</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>ticker</th>\n",
       "      <th>date</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th rowspan=\"10\" valign=\"top\">A</th>\n",
       "      <th>2001-04-30</th>\n",
       "      <td>-0.140220</td>\n",
       "      <td>-0.087246</td>\n",
       "      <td>-0.098192</td>\n",
       "      <td>0.269444</td>\n",
       "      <td>0.040966</td>\n",
       "      <td>-0.105747</td>\n",
       "      <td>-0.146389</td>\n",
       "      <td>-0.329564</td>\n",
       "      <td>-0.003653</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2001-05-31</th>\n",
       "      <td>-0.031008</td>\n",
       "      <td>-0.076414</td>\n",
       "      <td>-0.075527</td>\n",
       "      <td>-0.140220</td>\n",
       "      <td>0.044721</td>\n",
       "      <td>-0.023317</td>\n",
       "      <td>0.269444</td>\n",
       "      <td>-0.146389</td>\n",
       "      <td>-0.329564</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2001-06-30</th>\n",
       "      <td>-0.119692</td>\n",
       "      <td>-0.097014</td>\n",
       "      <td>-0.155847</td>\n",
       "      <td>-0.031008</td>\n",
       "      <td>-0.087246</td>\n",
       "      <td>0.018842</td>\n",
       "      <td>-0.140220</td>\n",
       "      <td>0.269444</td>\n",
       "      <td>-0.146389</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2001-07-31</th>\n",
       "      <td>-0.073750</td>\n",
       "      <td>-0.173364</td>\n",
       "      <td>-0.080114</td>\n",
       "      <td>-0.119692</td>\n",
       "      <td>-0.076414</td>\n",
       "      <td>-0.098192</td>\n",
       "      <td>-0.031008</td>\n",
       "      <td>-0.140220</td>\n",
       "      <td>0.269444</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2001-08-31</th>\n",
       "      <td>-0.262264</td>\n",
       "      <td>-0.083279</td>\n",
       "      <td>0.009593</td>\n",
       "      <td>-0.073750</td>\n",
       "      <td>-0.097014</td>\n",
       "      <td>-0.075527</td>\n",
       "      <td>-0.119692</td>\n",
       "      <td>-0.031008</td>\n",
       "      <td>-0.140220</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2001-09-30</th>\n",
       "      <td>0.139130</td>\n",
       "      <td>0.181052</td>\n",
       "      <td>0.134010</td>\n",
       "      <td>-0.262264</td>\n",
       "      <td>-0.173364</td>\n",
       "      <td>-0.155847</td>\n",
       "      <td>-0.073750</td>\n",
       "      <td>-0.119692</td>\n",
       "      <td>-0.031008</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2001-10-31</th>\n",
       "      <td>0.224517</td>\n",
       "      <td>0.131458</td>\n",
       "      <td>0.108697</td>\n",
       "      <td>0.139130</td>\n",
       "      <td>-0.083279</td>\n",
       "      <td>-0.080114</td>\n",
       "      <td>-0.262264</td>\n",
       "      <td>-0.073750</td>\n",
       "      <td>-0.119692</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2001-11-30</th>\n",
       "      <td>0.045471</td>\n",
       "      <td>0.054962</td>\n",
       "      <td>0.045340</td>\n",
       "      <td>0.224517</td>\n",
       "      <td>0.181052</td>\n",
       "      <td>0.009593</td>\n",
       "      <td>0.139130</td>\n",
       "      <td>-0.262264</td>\n",
       "      <td>-0.073750</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2001-12-31</th>\n",
       "      <td>0.064539</td>\n",
       "      <td>0.045275</td>\n",
       "      <td>0.070347</td>\n",
       "      <td>0.045471</td>\n",
       "      <td>0.131458</td>\n",
       "      <td>0.134010</td>\n",
       "      <td>0.224517</td>\n",
       "      <td>0.139130</td>\n",
       "      <td>-0.262264</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2002-01-31</th>\n",
       "      <td>0.026359</td>\n",
       "      <td>0.073264</td>\n",
       "      <td>-0.003306</td>\n",
       "      <td>0.064539</td>\n",
       "      <td>0.054962</td>\n",
       "      <td>0.108697</td>\n",
       "      <td>0.045471</td>\n",
       "      <td>0.224517</td>\n",
       "      <td>0.139130</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                   target_1m  target_2m  target_3m  return_1m  return_2m  \\\n",
       "ticker date                                                                \n",
       "A      2001-04-30  -0.140220  -0.087246  -0.098192   0.269444   0.040966   \n",
       "       2001-05-31  -0.031008  -0.076414  -0.075527  -0.140220   0.044721   \n",
       "       2001-06-30  -0.119692  -0.097014  -0.155847  -0.031008  -0.087246   \n",
       "       2001-07-31  -0.073750  -0.173364  -0.080114  -0.119692  -0.076414   \n",
       "       2001-08-31  -0.262264  -0.083279   0.009593  -0.073750  -0.097014   \n",
       "       2001-09-30   0.139130   0.181052   0.134010  -0.262264  -0.173364   \n",
       "       2001-10-31   0.224517   0.131458   0.108697   0.139130  -0.083279   \n",
       "       2001-11-30   0.045471   0.054962   0.045340   0.224517   0.181052   \n",
       "       2001-12-31   0.064539   0.045275   0.070347   0.045471   0.131458   \n",
       "       2002-01-31   0.026359   0.073264  -0.003306   0.064539   0.054962   \n",
       "\n",
       "                   return_3m  return_1m_t-1  return_1m_t-2  return_1m_t-3  \n",
       "ticker date                                                                \n",
       "A      2001-04-30  -0.105747      -0.146389      -0.329564      -0.003653  \n",
       "       2001-05-31  -0.023317       0.269444      -0.146389      -0.329564  \n",
       "       2001-06-30   0.018842      -0.140220       0.269444      -0.146389  \n",
       "       2001-07-31  -0.098192      -0.031008      -0.140220       0.269444  \n",
       "       2001-08-31  -0.075527      -0.119692      -0.031008      -0.140220  \n",
       "       2001-09-30  -0.155847      -0.073750      -0.119692      -0.031008  \n",
       "       2001-10-31  -0.080114      -0.262264      -0.073750      -0.119692  \n",
       "       2001-11-30   0.009593       0.139130      -0.262264      -0.073750  \n",
       "       2001-12-31   0.134010       0.224517       0.139130      -0.262264  \n",
       "       2002-01-31   0.108697       0.045471       0.224517       0.139130  "
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "cols = ['target_1m',\n",
    "        'target_2m',\n",
    "        'target_3m', \n",
    "        'return_1m',\n",
    "        'return_2m',\n",
    "        'return_3m',\n",
    "        'return_1m_t-1',\n",
    "        'return_1m_t-2',\n",
    "        'return_1m_t-3']\n",
    "\n",
    "data[cols].dropna().sort_index().head(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:55.272675Z",
     "start_time": "2020-06-16T21:40:55.207324Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "MultiIndex: 360752 entries, ('A', Timestamp('2001-01-31 00:00:00', freq='M')) to ('ZUMZ', Timestamp('2018-03-31 00:00:00', freq='M'))\n",
      "Data columns (total 30 columns):\n",
      " #   Column         Non-Null Count   Dtype  \n",
      "---  ------         --------------   -----  \n",
      " 0   return_1m      360752 non-null  float64\n",
      " 1   return_2m      360752 non-null  float64\n",
      " 2   return_3m      360752 non-null  float64\n",
      " 3   return_6m      360752 non-null  float64\n",
      " 4   return_9m      360752 non-null  float64\n",
      " 5   return_12m     360752 non-null  float64\n",
      " 6   Mkt-RF         360752 non-null  float64\n",
      " 7   SMB            360752 non-null  float64\n",
      " 8   HML            360752 non-null  float64\n",
      " 9   RMW            360752 non-null  float64\n",
      " 10  CMA            360752 non-null  float64\n",
      " 11  momentum_2     360752 non-null  float64\n",
      " 12  momentum_3     360752 non-null  float64\n",
      " 13  momentum_6     360752 non-null  float64\n",
      " 14  momentum_9     360752 non-null  float64\n",
      " 15  momentum_12    360752 non-null  float64\n",
      " 16  momentum_3_12  360752 non-null  float64\n",
      " 17  year           360752 non-null  int64  \n",
      " 18  month          360752 non-null  int64  \n",
      " 19  return_1m_t-1  358914 non-null  float64\n",
      " 20  return_1m_t-2  357076 non-null  float64\n",
      " 21  return_1m_t-3  355238 non-null  float64\n",
      " 22  return_1m_t-4  353400 non-null  float64\n",
      " 23  return_1m_t-5  351562 non-null  float64\n",
      " 24  return_1m_t-6  349724 non-null  float64\n",
      " 25  target_1m      358914 non-null  float64\n",
      " 26  target_2m      357076 non-null  float64\n",
      " 27  target_3m      355238 non-null  float64\n",
      " 28  target_6m      349724 non-null  float64\n",
      " 29  target_12m     338696 non-null  float64\n",
      "dtypes: float64(28), int64(2)\n",
      "memory usage: 94.1+ MB\n"
     ]
    }
   ],
   "source": [
    "data.info()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Create age proxy"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We use quintiles of IPO year as a proxy for company age."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:55.323385Z",
     "start_time": "2020-06-16T21:40:55.277174Z"
    }
   },
   "outputs": [],
   "source": [
    "data = (data\n",
    "        .join(pd.qcut(stocks.ipoyear, q=5, labels=list(range(1, 6)))\n",
    "              .astype(float)\n",
    "              .fillna(0)\n",
    "              .astype(int)\n",
    "              .to_frame('age')))\n",
    "data.age = data.age.fillna(-1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Create dynamic size proxy"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We use the marketcap information from the NASDAQ ticker info to create a size proxy."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:55.339294Z",
     "start_time": "2020-06-16T21:40:55.324681Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "Index: 2412 entries, A to ZUMZ\n",
      "Data columns (total 3 columns):\n",
      " #   Column     Non-Null Count  Dtype  \n",
      "---  ------     --------------  -----  \n",
      " 0   marketcap  2407 non-null   float64\n",
      " 1   ipoyear    1065 non-null   float64\n",
      " 2   sector     2372 non-null   object \n",
      "dtypes: float64(2), object(1)\n",
      "memory usage: 155.4+ KB\n"
     ]
    }
   ],
   "source": [
    "stocks.info()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Market cap information is tied to currrent prices. We create an adjustment factor to have the values reflect lower historical prices for each individual stock:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:55.487710Z",
     "start_time": "2020-06-16T21:40:55.342097Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "DatetimeIndex: 207 entries, 2018-03-31 to 2001-01-31\n",
      "Columns: 1838 entries, A to UFS\n",
      "dtypes: float64(1838)\n",
      "memory usage: 2.9 MB\n"
     ]
    }
   ],
   "source": [
    "size_factor = (monthly_prices\n",
    "               .loc[data.index.get_level_values('date').unique(),\n",
    "                    data.index.get_level_values('ticker').unique()]\n",
    "               .sort_index(ascending=False)\n",
    "               .pct_change()\n",
    "               .fillna(0)\n",
    "               .add(1)\n",
    "               .cumprod())\n",
    "size_factor.info()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:56.148120Z",
     "start_time": "2020-06-16T21:40:55.500803Z"
    }
   },
   "outputs": [],
   "source": [
    "msize = (size_factor\n",
    "         .mul(stocks\n",
    "              .loc[size_factor.columns, 'marketcap'])).dropna(axis=1, how='all')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Create Size indicator as deciles per period"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Compute size deciles per month:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:57.668269Z",
     "start_time": "2020-06-16T21:40:56.149716Z"
    }
   },
   "outputs": [],
   "source": [
    "data['msize'] = (msize\n",
    "                 .apply(lambda x: pd.qcut(x, q=10, labels=list(range(1, 11)))\n",
    "                        .astype(int), axis=1)\n",
    "                 .stack()\n",
    "                 .swaplevel())\n",
    "data.msize = data.msize.fillna(-1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Combine data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:57.770043Z",
     "start_time": "2020-06-16T21:40:57.670251Z"
    }
   },
   "outputs": [],
   "source": [
    "data = data.join(stocks[['sector']])\n",
    "data.sector = data.sector.fillna('Unknown')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:57.990888Z",
     "start_time": "2020-06-16T21:40:57.772004Z"
    },
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "MultiIndex: 360752 entries, ('A', Timestamp('2001-01-31 00:00:00', freq='M')) to ('ZUMZ', Timestamp('2018-03-31 00:00:00', freq='M'))\n",
      "Data columns (total 33 columns):\n",
      " #   Column         Non-Null Count   Dtype  \n",
      "---  ------         --------------   -----  \n",
      " 0   return_1m      360752 non-null  float64\n",
      " 1   return_2m      360752 non-null  float64\n",
      " 2   return_3m      360752 non-null  float64\n",
      " 3   return_6m      360752 non-null  float64\n",
      " 4   return_9m      360752 non-null  float64\n",
      " 5   return_12m     360752 non-null  float64\n",
      " 6   Mkt-RF         360752 non-null  float64\n",
      " 7   SMB            360752 non-null  float64\n",
      " 8   HML            360752 non-null  float64\n",
      " 9   RMW            360752 non-null  float64\n",
      " 10  CMA            360752 non-null  float64\n",
      " 11  momentum_2     360752 non-null  float64\n",
      " 12  momentum_3     360752 non-null  float64\n",
      " 13  momentum_6     360752 non-null  float64\n",
      " 14  momentum_9     360752 non-null  float64\n",
      " 15  momentum_12    360752 non-null  float64\n",
      " 16  momentum_3_12  360752 non-null  float64\n",
      " 17  year           360752 non-null  int64  \n",
      " 18  month          360752 non-null  int64  \n",
      " 19  return_1m_t-1  358914 non-null  float64\n",
      " 20  return_1m_t-2  357076 non-null  float64\n",
      " 21  return_1m_t-3  355238 non-null  float64\n",
      " 22  return_1m_t-4  353400 non-null  float64\n",
      " 23  return_1m_t-5  351562 non-null  float64\n",
      " 24  return_1m_t-6  349724 non-null  float64\n",
      " 25  target_1m      358914 non-null  float64\n",
      " 26  target_2m      357076 non-null  float64\n",
      " 27  target_3m      355238 non-null  float64\n",
      " 28  target_6m      349724 non-null  float64\n",
      " 29  target_12m     338696 non-null  float64\n",
      " 30  age            360752 non-null  int64  \n",
      " 31  msize          360752 non-null  float64\n",
      " 32  sector         360752 non-null  object \n",
      "dtypes: float64(29), int64(3), object(1)\n",
      "memory usage: 102.3+ MB\n"
     ]
    }
   ],
   "source": [
    "data.info()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Store data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We will use the data again in several later chapters, starting in [Chapter 7 on Linear Models](../../07_linear_models/README.md)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:58.632330Z",
     "start_time": "2020-06-16T21:40:58.003188Z"
    },
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.io.pytables.HDFStore'>\n",
      "File path: ../../data/assets.h5\n",
      "/engineered_features            frame        (shape->[358914,33])  \n",
      "/quandl/wiki/prices             frame        (shape->[15389314,12])\n",
      "/quandl/wiki/stocks             frame        (shape->[1,2])        \n",
      "/sp500/fred                     frame        (shape->[2609,1])     \n",
      "/sp500/sp500_stooq              frame        (shape->[17700,5])    \n",
      "/sp500/stocks                   frame        (shape->[1,7])        \n",
      "/us_equities/stocks             frame        (shape->[6834,6])     \n"
     ]
    }
   ],
   "source": [
    "with pd.HDFStore(DATA_STORE) as store:\n",
    "    store.put('engineered_features', data.sort_index().loc[idx[:, :datetime(2018, 3, 1)], :])\n",
    "    print(store.info())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Create Dummy variables"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For most models, we need to encode categorical variables as 'dummies' (one-hot encoding):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-06-16T21:40:59.182315Z",
     "start_time": "2020-06-16T21:40:58.638055Z"
    },
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'pandas.core.frame.DataFrame'>\n",
      "MultiIndex: 360752 entries, ('A', Timestamp('2001-01-31 00:00:00', freq='M')) to ('ZUMZ', Timestamp('2018-03-31 00:00:00', freq='M'))\n",
      "Data columns (total 88 columns):\n",
      " #   Column                 Non-Null Count   Dtype  \n",
      "---  ------                 --------------   -----  \n",
      " 0   return_1m              360752 non-null  float64\n",
      " 1   return_2m              360752 non-null  float64\n",
      " 2   return_3m              360752 non-null  float64\n",
      " 3   return_6m              360752 non-null  float64\n",
      " 4   return_9m              360752 non-null  float64\n",
      " 5   return_12m             360752 non-null  float64\n",
      " 6   Mkt-RF                 360752 non-null  float64\n",
      " 7   SMB                    360752 non-null  float64\n",
      " 8   HML                    360752 non-null  float64\n",
      " 9   RMW                    360752 non-null  float64\n",
      " 10  CMA                    360752 non-null  float64\n",
      " 11  momentum_2             360752 non-null  float64\n",
      " 12  momentum_3             360752 non-null  float64\n",
      " 13  momentum_6             360752 non-null  float64\n",
      " 14  momentum_9             360752 non-null  float64\n",
      " 15  momentum_12            360752 non-null  float64\n",
      " 16  momentum_3_12          360752 non-null  float64\n",
      " 17  return_1m_t-1          358914 non-null  float64\n",
      " 18  return_1m_t-2          357076 non-null  float64\n",
      " 19  return_1m_t-3          355238 non-null  float64\n",
      " 20  return_1m_t-4          353400 non-null  float64\n",
      " 21  return_1m_t-5          351562 non-null  float64\n",
      " 22  return_1m_t-6          349724 non-null  float64\n",
      " 23  target_1m              358914 non-null  float64\n",
      " 24  target_2m              357076 non-null  float64\n",
      " 25  target_3m              355238 non-null  float64\n",
      " 26  target_6m              349724 non-null  float64\n",
      " 27  target_12m             338696 non-null  float64\n",
      " 28  year_2001              360752 non-null  uint8  \n",
      " 29  year_2002              360752 non-null  uint8  \n",
      " 30  year_2003              360752 non-null  uint8  \n",
      " 31  year_2004              360752 non-null  uint8  \n",
      " 32  year_2005              360752 non-null  uint8  \n",
      " 33  year_2006              360752 non-null  uint8  \n",
      " 34  year_2007              360752 non-null  uint8  \n",
      " 35  year_2008              360752 non-null  uint8  \n",
      " 36  year_2009              360752 non-null  uint8  \n",
      " 37  year_2010              360752 non-null  uint8  \n",
      " 38  year_2011              360752 non-null  uint8  \n",
      " 39  year_2012              360752 non-null  uint8  \n",
      " 40  year_2013              360752 non-null  uint8  \n",
      " 41  year_2014              360752 non-null  uint8  \n",
      " 42  year_2015              360752 non-null  uint8  \n",
      " 43  year_2016              360752 non-null  uint8  \n",
      " 44  year_2017              360752 non-null  uint8  \n",
      " 45  year_2018              360752 non-null  uint8  \n",
      " 46  month_1                360752 non-null  uint8  \n",
      " 47  month_2                360752 non-null  uint8  \n",
      " 48  month_3                360752 non-null  uint8  \n",
      " 49  month_4                360752 non-null  uint8  \n",
      " 50  month_5                360752 non-null  uint8  \n",
      " 51  month_6                360752 non-null  uint8  \n",
      " 52  month_7                360752 non-null  uint8  \n",
      " 53  month_8                360752 non-null  uint8  \n",
      " 54  month_9                360752 non-null  uint8  \n",
      " 55  month_10               360752 non-null  uint8  \n",
      " 56  month_11               360752 non-null  uint8  \n",
      " 57  month_12               360752 non-null  uint8  \n",
      " 58  msize_-1               360752 non-null  uint8  \n",
      " 59  msize_1                360752 non-null  uint8  \n",
      " 60  msize_2                360752 non-null  uint8  \n",
      " 61  msize_3                360752 non-null  uint8  \n",
      " 62  msize_4                360752 non-null  uint8  \n",
      " 63  msize_5                360752 non-null  uint8  \n",
      " 64  msize_6                360752 non-null  uint8  \n",
      " 65  msize_7                360752 non-null  uint8  \n",
      " 66  msize_8                360752 non-null  uint8  \n",
      " 67  msize_9                360752 non-null  uint8  \n",
      " 68  msize_10               360752 non-null  uint8  \n",
      " 69  age_0                  360752 non-null  uint8  \n",
      " 70  age_1                  360752 non-null  uint8  \n",
      " 71  age_2                  360752 non-null  uint8  \n",
      " 72  age_3                  360752 non-null  uint8  \n",
      " 73  age_4                  360752 non-null  uint8  \n",
      " 74  age_5                  360752 non-null  uint8  \n",
      " 75  Basic Industries       360752 non-null  uint8  \n",
      " 76  Capital Goods          360752 non-null  uint8  \n",
      " 77  Consumer Durables      360752 non-null  uint8  \n",
      " 78  Consumer Non-Durables  360752 non-null  uint8  \n",
      " 79  Consumer Services      360752 non-null  uint8  \n",
      " 80  Energy                 360752 non-null  uint8  \n",
      " 81  Finance                360752 non-null  uint8  \n",
      " 82  Health Care            360752 non-null  uint8  \n",
      " 83  Miscellaneous          360752 non-null  uint8  \n",
      " 84  Public Utilities       360752 non-null  uint8  \n",
      " 85  Technology             360752 non-null  uint8  \n",
      " 86  Transportation         360752 non-null  uint8  \n",
      " 87  Unknown                360752 non-null  uint8  \n",
      "dtypes: float64(28), uint8(60)\n",
      "memory usage: 99.1+ MB\n"
     ]
    }
   ],
   "source": [
    "dummy_data = pd.get_dummies(data,\n",
    "                            columns=['year','month', 'msize', 'age',  'sector'],\n",
    "                            prefix=['year','month', 'msize', 'age', ''],\n",
    "                            prefix_sep=['_', '_', '_', '_', ''])\n",
    "dummy_data = dummy_data.rename(columns={c:c.replace('.0', '') for c in dummy_data.columns})\n",
    "dummy_data.info()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.7"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": true,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "230.355px"
   },
   "toc_section_display": true,
   "toc_window_display": true
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}